/*
 * Copyright 2022 Huawei Cloud Computing Technology Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.huawei.cloudapp.ui;

import android.app.Activity;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

import androidx.fragment.app.FragmentActivity;

import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.ProgressBar;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.RelativeLayout;
import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast;

import com.google.gson.Gson;
import com.huawei.cloudapp.BuildConfig;
import com.huawei.cloudapp.R;
import com.huawei.cloudapp.common.CASLog;
import com.huawei.cloudapp.common.CasCommonDialog;
import com.huawei.cloudapp.common.CasConnectInfo;
import com.huawei.cloudapp.common.CasHistory;
import com.huawei.cloudapp.common.CasImageQualityManager;
import com.huawei.cloudapp.common.CasListener;
import com.huawei.cloudapp.common.CasState;
import com.huawei.cloudapp.utils.CasAdaptPhoneUtils;
import com.huawei.cloudphone.api.CloudAppDataListener;
import com.huawei.cloudphone.api.CloudPhoneManager;
import com.huawei.cloudphone.api.CloudPhoneOrientationChangeListener;
import com.huawei.cloudphone.api.CloudPhoneParas;
import com.huawei.cloudphone.api.CloudPhoneStateListener;
import com.huawei.cloudphone.api.CloudPhoneVirtualDevDataListener;
import com.huawei.cloudphone.api.ICloudPhone;
import com.huawei.cloudphone.virtualdevice.VirtualDeviceSession;
import com.huawei.cloudphone.virtualdevice.common.RingBufferVirtualDeviceIO;
import com.petterp.floatingx.assist.FxGravity;
import com.petterp.floatingx.assist.helper.ScopeHelper;

import java.util.HashMap;

import static android.os.SystemClock.sleep;
import static com.huawei.cloudapp.common.CasImageQualityManager.QUALITY_MAIN;
import static com.huawei.cloudapp.common.CasImageQualityManager.QUALITY_BASIC;
import static com.huawei.cloudapp.common.CasImageQualityManager.QUALITY_BEST;
import static com.huawei.cloudapp.utils.CasConstantsUtil.AES_KEY;
import static com.huawei.cloudapp.utils.CasConstantsUtil.AUTH_TS;
import static com.huawei.cloudapp.utils.CasConstantsUtil.AVAILABLE_PLAYTIME;
import static com.huawei.cloudapp.utils.CasConstantsUtil.BACKGROUND_TIMEOUT;
import static com.huawei.cloudapp.utils.CasConstantsUtil.DEFINITION_BASIC;
import static com.huawei.cloudapp.utils.CasConstantsUtil.DEFINITION_BEST;
import static com.huawei.cloudapp.utils.CasConstantsUtil.DEFINITION_MAIN;
import static com.huawei.cloudapp.utils.CasConstantsUtil.FRAME_TYPE_H265;
import static com.huawei.cloudapp.utils.CasConstantsUtil.IP;
import static com.huawei.cloudapp.utils.CasConstantsUtil.PORT;
import static com.huawei.cloudapp.utils.CasConstantsUtil.RESOLUTION_1080P;
import static com.huawei.cloudapp.utils.CasConstantsUtil.SESSION_ID;
import static com.huawei.cloudapp.utils.CasConstantsUtil.TICKET;
import static com.huawei.cloudapp.utils.CasConstantsUtil.TOUCH_TIMEOUT;
import static com.huawei.cloudapp.utils.CasConstantsUtil.USER_ID;
import static com.huawei.cloudphone.api.CloudPhoneParas.DevType.DEV_PHONE;
import static com.huawei.cloudphone.utils.CasConstantsUtil.FRAME_TYPE;
import static com.huawei.cloudphone.utils.CasConstantsUtil.PHYSICAL_HEIGHT;
import static com.huawei.cloudphone.utils.CasConstantsUtil.PHYSICAL_WIDTH;
import static com.huawei.cloudphone.utils.CasConstantsUtil.QUALITY;
import static com.huawei.cloudphone.utils.CasConstantsUtil.WIDTH;
import static com.huawei.cloudphone.utils.CasMediaUtils.isSupportH265;
import static com.huawei.cloudphone.virtualdevice.camera.VirtualCameraManager.GRANT_CAMERA_PERMISSION_SUCCESS_ACTION;
import static com.huawei.cloudphone.virtualdevice.common.VirtualDeviceManager.DEV_TYPE_CAMERA;
import static com.huawei.cloudphone.virtualdevice.common.VirtualDeviceManager.DEV_TYPE_MICROPHONE;
import static com.huawei.cloudphone.virtualdevice.microphone.VirtualMicrophoneManager.GRANT_MICROPHONE_PERMISSION_SUCCESS_ACTION;

public class CasCloudPhoneActivity extends FragmentActivity implements View.OnClickListener {
    private static final String TAG = "CasCloudPhoneActivity";

    // Intent Trans Key
    public static final String ORIENTATION = "orientation";
    public static final String CUSTOM_VIEW = "custom_view";
    public static final String DISPLAY_MODE = "display_mode";
    public static final String DEV_TYPE = "device_type";
    public static final String MEDIA_CONFIG = "media_config";

    // resident lag
    public static final String RESIDENT_LAG_FORMAT = "LAG: ";
    public static final String RESIDENT_LAG_UNIT_FORMAT = " ms";
    public static final int REFERENCE_LAG_MAX_VALUE = 500;
    public static final int REFERENCE_LAG_MID_VALUE = 300;
    public static final int REFERENCE_LAG_MIN_VALUE = 200;
    public static final int REFERENCE_LAG_ZERO_VALUE = 0;
    public static final int CAMERA_PERMISSION_REQUEST_CODE = 0;
    public static final int RECORD_AUDIO_PERMISSION_REQUEST_CODE = 1;
    private static final int CHANGE_ROTA = 100;
    private static final int MSG_CONNECT_FAILED = 102;
    private static final int MSG_STATE_CHANGE = 103;
    private static final int MSG_SHOW_TRAIL_PLAY_TIMEOUT = 104;
    private static final int MSG_RECONNECT_FAILED = 105;
    private static CasCloudPhoneActivity gAcitivity = null;
    private static CasListener mCasListener = null;

    // flag
    public volatile boolean rebuildDone = false;
    public boolean doCheckConnection = false;
    private int mDevType;
    private HashMap<String, String> mMediaConfig = null;
    private ProgressBar mProgressBar = null;
    private int currentRotation = -1;
    private CasCommonDialog quitDialog;
    private CasCommonDialog mDialog;
    private CasHistory mCasHistory;

    //virtual devices
    VirtualDeviceSession mVirtualDeviceSession = null;
    RingBufferVirtualDeviceIO mRingBufferVirtualDeviceIO = null;

    // debug info
    private boolean isShowingLagInfoView;
    private Switch lagSwitch;
    private TextView textCtrl;
    private RelativeLayout ctrView;
    private TextView mQuitCloudPhone;

    // intent trans value
    private CasConnectInfo connectInfo;
    private RadioGroup qualityRadioViewGroup;
    private RadioButton radioViewBest;
    private RadioButton radioViewMain;
    private RadioButton radioViewBasic;
    private boolean bIsStart = false;
    private boolean isGotCameraAndRecordPermission = true;
    private int mOrientation = 0;
    private String mFrameType = FRAME_TYPE_H265;
    private String mResolution = RESOLUTION_1080P;
    private int mDisplayMode;
    private FrameLayout mFrameLayout = null;
    private FrameLayout mFloatContainer = null;
    private boolean mIsTrailPlayTimeout = false;
    private boolean mIsActivityBackground = false;
    private volatile boolean mIsStartTaskRunning = false;
    private ICloudPhone mCloudPhone;

    RadioGroup.OnCheckedChangeListener qualityCheckedChangeListener = new RadioGroup.OnCheckedChangeListener() {
        public void onCheckedChanged(RadioGroup group, int checkedId) {
            if (group.getCheckedRadioButtonId() != checkedId) {
                CASLog.e("CasMainActivity", "group.getCheckedRadioButtonId() != checkedId");
            } else {
                int selectType = QUALITY_MAIN;
                String quality = DEFINITION_MAIN;
                if (radioViewBest.getId() == checkedId) {
                    selectType = QUALITY_BEST;
                    quality = DEFINITION_BEST;
                } else if (radioViewMain.getId() == checkedId) {
                    selectType = QUALITY_MAIN;
                    quality = DEFINITION_MAIN;
                } else if (radioViewBasic.getId() == checkedId) {
                    selectType = QUALITY_BASIC;
                    quality = DEFINITION_BASIC;
                }

                int oldSelectType = CasImageQualityManager.getInstance().getImageQualityStatus();
                resumeImageQualityStatus(oldSelectType);
                CasImageQualityManager.getInstance().setImageQualityStatus(selectType);
                checkImageQualityStatus(selectType);
                HashMap<String, String> config = new HashMap<>();
                config.put(QUALITY, quality);
                mCloudPhone.setMediaConfig(config);
            }
            if (ctrView != null && ctrView.getVisibility() == View.VISIBLE) {
                ctrView.setVisibility(View.GONE);
            }
        }
    };
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case CHANGE_ROTA:
                    CASLog.d(TAG, "--->CHANGE_ROTA:%d", msg.arg1);
                    setRotation(msg.arg1);
                    break;
                case MSG_CONNECT_FAILED:
                    showDialog(getResources().getString(R.string.cas_phone_connect_server_fail_tip_message));
                    break;
                case MSG_SHOW_TRAIL_PLAY_TIMEOUT:
                    CASLog.i(TAG, "showPlayTimeoutDialog...");
                    showDialog(getResources().getString(R.string.cas_phone_play_timeout_tip_message));
                    break;
                case MSG_STATE_CHANGE:
                    processStateChangeMsg(msg.arg1, (String) msg.obj);
                    break;
                case MSG_RECONNECT_FAILED:
                    showDialog(getResources().getString(R.string.cas_phone_reconnect_server_fail_tip_message));
                    break;
                default:
                    break;
            }
        }
    };

    /**
     * set screen long light
     */
    public static void keepScreenLongLight(Activity activity, boolean isOpenLight) {
        CASLog.d(TAG, "@keepScreenLongLight isOpenLight=" + isOpenLight);
        Window window = activity.getWindow();
        if (isOpenLight) {
            window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        } else {
            window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        }
    }

    /**
     * Activity:onCreate
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        setFullScreen();
        super.onCreate(savedInstanceState);
        setContentView(R.layout.cas_activity_fullscreen);
        keepScreenLongLight(this, true);
        getIntentData();
        initVirtualDeviceSession();
        mCasHistory = new CasHistory(getSharedPreferences("input_history", MODE_PRIVATE));
        // get views
        mProgressBar = findViewById(R.id.loading_progress_bar);
        mFrameLayout = (FrameLayout) findViewById(R.id.frame_layout);
        mFloatContainer = (FrameLayout) findViewById(R.id.floatContainer);
        lagSwitch = (Switch) findViewById(R.id.lag_switch);
        lagSwitch.setOnClickListener(CasCloudPhoneActivity.this);
        ctrView = (RelativeLayout) findViewById(R.id.ctr_view);
        ctrView.setOnClickListener(CasCloudPhoneActivity.this);
        mQuitCloudPhone = (TextView) findViewById(R.id.quit_cloud_phone);
        mQuitCloudPhone.setOnClickListener(CasCloudPhoneActivity.this);
        // ctrlView
        qualityRadioViewGroup = findViewById(R.id.pic_quality_choose_layout);
        radioViewBest = findViewById(R.id.pic_quality_best);
        radioViewMain = findViewById(R.id.pic_quality_main);
        radioViewBasic = findViewById(R.id.pic_quality_basic);
        qualityRadioViewGroup.setVisibility(View.GONE);
        qualityRadioViewGroup.check(radioViewMain.getId());
        qualityRadioViewGroup.setOnCheckedChangeListener(qualityCheckedChangeListener);

        float dp = getResources().getDisplayMetrics().density;
        ScopeHelper.builder().setLayout(R.layout.cas_ctrl_button_view).
                setEnableEdgeAdsorption(true).
                setEdgeOffset(10f).
                setEnableScrollOutsideScreen(true).
                setGravity(FxGravity.LEFT_OR_TOP).
                setEnableAssistDirection(150 * dp, 0f, 0f, 0f).
                build().toControl(this).show();
        textCtrl = (TextView) findViewById(R.id.tv_ctrl);
        textCtrl.setOnClickListener(CasCloudPhoneActivity.this);
        textCtrl.setBackgroundResource(R.drawable.button_sub_action_selector);

        setRotation(mOrientation);
        lagSwitch.setChecked(false);
        gAcitivity = this;
        try {
            mCloudPhone = CloudPhoneManager.createCloudPhoneInstance();
            mCloudPhone.setDisplayMode(CloudPhoneParas.DisplayMode.DISPLAY_MODE_FILL);
            mCloudPhone.init(this, DEV_PHONE);

            HashMap<String, String> parasMap = new HashMap<String, String>();
            parasMap.put(IP, connectInfo.getConnectIp());
            parasMap.put(PORT, connectInfo.getConnectPort());
            parasMap.put(SESSION_ID, connectInfo.getSessionId());
            parasMap.put(TICKET, connectInfo.getTicket());
            parasMap.put(AES_KEY, connectInfo.getAesKey());
            parasMap.put(AUTH_TS, connectInfo.getAuthTs());
            parasMap.put(BACKGROUND_TIMEOUT, connectInfo.getBackgroundTimeout());
            parasMap.put(AVAILABLE_PLAYTIME, connectInfo.getAvailablePlayTime());
            parasMap.put(USER_ID, connectInfo.getUserId());
            parasMap.put(TOUCH_TIMEOUT, connectInfo.getTouchTimeout());
            mCloudPhone.registerCloudPhoneStateListener(new CloudPhoneStateListenerImpl());
            mCloudPhone.registerOnOrientationChangeListener(new CloudPhoneOrientationListener());
            mCloudPhone.registerOnVirtualDevDataListener(new CloudPhoneVirtualDevDataListenerImpl());
            mCloudPhone.registerCloudAppDataListener(new CloudAppDataListener() {
                @Override
                public void onRecvCloudAppData(byte[] data) {
                    CASLog.i(TAG, "onRecvCloudAppData, data size: %d", data.length);
                }
            });

            if (mMediaConfig == null) {
                mMediaConfig = new HashMap<String, String>();
            }
            if (isSupportH265()) {
                mMediaConfig.put(FRAME_TYPE, "h265");
            } else {
                mMediaConfig.put(FRAME_TYPE, "h264");
            }

            mMediaConfig.put(QUALITY, DEFINITION_MAIN);
            DisplayMetrics metrics = new DisplayMetrics();
            getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
            mMediaConfig.put(PHYSICAL_WIDTH, String.valueOf(metrics.widthPixels));
            mMediaConfig.put(PHYSICAL_HEIGHT, String.valueOf(metrics.heightPixels));

            mCloudPhone.setMediaConfig(mMediaConfig);
            mCloudPhone.startCloudPhone(this, mFrameLayout, parasMap);
        } catch (IllegalArgumentException e) {
            showDialog(getResources().getString(R.string.cas_phone_input_param_invalid));
        } catch (Exception e) {
            CASLog.e(TAG, "startCloudApp start failed." + e.getMessage());
            showDialog(getResources().getString(R.string.cas_phone_start_fail_tip_message));
        }
    }

    /**
     * Activity:onStart
     */
    @Override
    public void onStart() {
        CASLog.i(TAG, "onStart");
        super.onStart();
    }

    /**
     * Activity:onRestart
     */
    @Override
    public void onRestart() {
        CASLog.i(TAG, "onRestart");
        super.onRestart();
    }

    /**
     * Activity:onStop
     */
    @Override
    public void onStop() {
        CASLog.i(TAG, "onStop");
        super.onStop();
        mCloudPhone.mute();
    }

    /**
     * Activity:onPause
     */
    @Override
    public void onPause() {
        CASLog.i(TAG, "onPause");
        super.onPause();
        bIsStart = false;
        mIsActivityBackground = true;
    }

    /**
     * Activity:onResume
     */
    @Override
    public void onResume() {
        CASLog.i(TAG, "onResume");
        if (mIsActivityBackground) {
            setFullScreen();
        }
        mIsActivityBackground = false;
        super.onResume();
        if (mIsTrailPlayTimeout) {
            CASLog.i(TAG, "trail play timeout");
            Message message = new Message();
            message.what = MSG_SHOW_TRAIL_PLAY_TIMEOUT;
            handler.sendMessage(message);
        }
        mCloudPhone.unmute();
    }

    /**
     * Activity:onDestroy
     */
    @Override
    protected void onDestroy() {
        CASLog.i(TAG, "onDestroy");
        keepScreenLongLight(this, false);
        super.onDestroy();
        try {
            mCloudPhone.exitCloudPhone();
            mCloudPhone.deinit();
        } catch (Exception e) {
            CASLog.e(TAG, "destroy failed. " + e.getMessage());
        }
        Intent intent = new Intent("com.huawei.cloudapp.ui.CasCloudPhoneActivity.destroyed");
        sendBroadcast(intent);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == DEV_TYPE_CAMERA) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                this.sendBroadcast(new Intent(GRANT_CAMERA_PERMISSION_SUCCESS_ACTION));
            }
        } else if (requestCode == DEV_TYPE_MICROPHONE) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                this.sendBroadcast(new Intent(GRANT_MICROPHONE_PERMISSION_SUCCESS_ACTION));
            }
        }
    }

    /**
     * get data with intent
     */
    private void getIntentData() {
        CASLog.i(TAG, "getIntentData");
        Intent intent = getIntent();
        Bundle bundle = intent.getExtras();
        if (bundle != null) {
            connectInfo = intent.getParcelableExtra(CasConnectInfo.BUNDLE_KEY);
            mOrientation = bundle.getInt(ORIENTATION);
            mDisplayMode = bundle.getInt(DISPLAY_MODE);
            mDevType = bundle.getInt(DEV_TYPE);
            mMediaConfig = (HashMap<String, String>) bundle.getSerializable(MEDIA_CONFIG);
        }
    }

    private void initVirtualDeviceSession() {
        if (!isGotCameraAndRecordPermission) return;
        mVirtualDeviceSession = new VirtualDeviceSession(this);
        mRingBufferVirtualDeviceIO = new RingBufferVirtualDeviceIO();
        mVirtualDeviceSession.setVirtualDeviceIoHook(mRingBufferVirtualDeviceIO);
    }

    private void processStateChangeMsg(int code, String msg) {
        CASLog.i(TAG, "processStateChangeMsg code = " + code);
        switch (code) {
            case CasState.CAS_START_SUCCESS:
                mProgressBar.setVisibility(View.GONE);
                startSuccessThreadTask();
                handleStartSuccessMsg(msg);
                mCasHistory.setHistory("ip", connectInfo.getConnectIp());
                mCasHistory.setHistory("port", connectInfo.getConnectPort());
                mCasHistory.setHistory("ip:port", connectInfo.getConnectIp() + ":" + connectInfo.getConnectPort());
                if (mVirtualDeviceSession != null) {
                    mVirtualDeviceSession.start();
                }
                break;
            case CasState.CAS_SERVER_UNREACHABLE:
                showDialog(getResources().getString(R.string.cas_phone_connect_server_fail_tip_message));
                break;
            case CasState.CAS_ENGINE_START_FAILED:
            case CasState.CAS_PARAMETER_MISSING:
                showDialog(getResources().getString(R.string.cas_phone_start_fail_tip_message));
                break;
            case CasState.CAS_RESOURCE_IN_USING:
                showDialog(getResources().getString(R.string.cas_phone_resource_inusing_tip_message));
                break;
            case CasState.CAS_INVALID_CMD:
                showDialog(getResources().getString(R.string.cas_phone_invalid_cmd_tip_message));
                break;
            case CasState.CAS_VERIFY_PARAMETER_MISSING:
            case CasState.CAS_VERIFY_PARAMETER_INVALID:
            case CasState.CAS_VERIFY_AESKEY_QUERY_FAILED:
            case CasState.CAS_VERIFY_AESKEY_INVALID:
            case CasState.CAS_VERIFY_DECRYPT_FAILED:
            case CasState.CAS_VERIFY_FAILED:
                showDialog(getResources().getString(R.string.cas_phone_start_auth_fail_tip_message));
                break;
            case CasState.CAS_VERIFY_SESSION_ID_INVALID:
                try {
                    mCloudPhone.exitCloudPhone();
                } catch (Exception e) {
                    CASLog.e(TAG, "Stop cloud phone failed. ", e.getMessage());
                }
                showDialog(getResources().getString(R.string.cas_phone_session_invalid_tip_message));
                break;
            case CasState.CAS_TRAIL_PLAY_TIMEOUT:
                mIsTrailPlayTimeout = true;
                if (!mIsActivityBackground) {
                    CASLog.i(TAG, "avtivity running foreground");
                    showDialog(getResources().getString(R.string.cas_phone_play_timeout_tip_message));
                } else {
                    CASLog.i(TAG, "avtivity running background");
                }
                break;
            case CasState.CAS_BACKGROUND_TIMEOUT:
                stopCloudPhone();
                break;
            case CasState.CAS_SWITCH_FOREGROUND_SUCCESS:
                startSuccessThreadTask();
                break;
            case CasState.CAS_CONNECT_LOST:
                showDialog(getResources().getString(R.string.cas_phone_reconnect_server_fail_tip_message));
                break;
            // 切home网络断开，切到前台会尝试重连，重连成功后需要启动网络监控和状态获取任务
            case CasState.CAS_RECONNECT_SUCCESS:
                CASLog.i(TAG, "mIsStartTaskRunning = " + mIsStartTaskRunning);
                break;
            case CasState.CAS_NOTOUCH_TIMEOUT:
                showDialog(getResources().getString(R.string.cas_notouch_timeout_tip_message));
                break;
            default:
                break;
        }
    }

    private void handleStartSuccessMsg(String msg) {
        if (mMediaConfig == null) {
            mMediaConfig = new HashMap<String, String>();
        }

        Gson gson = new Gson();
        HashMap<String, Object> cloudMediaConfig = gson.fromJson(msg, new HashMap<String, Object>().getClass());
        mResolution = String.valueOf(((Double) cloudMediaConfig.get(WIDTH)).intValue());
        mFrameType = (String) cloudMediaConfig.get(FRAME_TYPE);
        CASLog.i(TAG, "mResolution = " + mResolution + ", mFrameType = " + mFrameType);
        if (mResolution.equals(RESOLUTION_1080P)) {
            radioViewBest.setText(R.string.quality_UHD);
            radioViewMain.setText(R.string.quality_HD);
            radioViewBasic.setText(R.string.quality_SD);
        }
        qualityRadioViewGroup.setVisibility(View.VISIBLE);
    }

    /**
     * set full screen display
     */
    private void setFullScreen() {
        CASLog.d(TAG, "@setFullScreen: FEATURE_NO_TITLE & FLAG_FULLSCREEN");

        Window window = getWindow();
        WindowManager.LayoutParams params = window.getAttributes();

        // set full screen
        window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        int vis = window.getDecorView().getSystemUiVisibility();
        window.getDecorView().setSystemUiVisibility(vis
                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);

        if (Build.VERSION.SDK_INT >= 28) {
            // Adapt by setting parameters
            params.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
        } else {
            CasAdaptPhoneUtils.getInstance().adaptPhoneNotch(this, params);
        }

        params.systemUiVisibility = View.INVISIBLE;
        window.setAttributes(params);
    }

    /**
     * main thread set rotation
     */
    public void setRotation(int rotation) {
        if (rotation > 24) {
            return;
        }
        if (currentRotation != rotation) {
            switch (rotation) {
                case 0:
                    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
                    break;
                case 1:
                case 8:
                    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
                    break;
                case 2:
                case 16:
                    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
                    break;
                case 3:
                case 24:
                    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
                    break;
                default:
                    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
                    break;
            }
            currentRotation = rotation;
        }
    }

    /**
     * update lag info view state
     */
    public void updateLagInfoViewState(Boolean isChecked) {
        isShowingLagInfoView = isChecked;
        if (!isShowingLagInfoView) {
            textCtrl.setText("CTRL");
            textCtrl.setTextColor(getResources().getColor(R.color.black));
        }
    }

    /**
     * set the color of the selected image quality
     */
    private void checkImageQualityStatus(int selectType) {
        switch (selectType) {
            case QUALITY_BASIC:
                radioViewBasic.setTextColor(this.getResources().getColor(R.color.cas_colorAccent));
                break;
            case QUALITY_MAIN:
                radioViewMain.setTextColor(this.getResources().getColor(R.color.cas_colorAccent));
                break;
            case QUALITY_BEST:
                radioViewBest.setTextColor(this.getResources().getColor(R.color.cas_colorAccent));
                break;
            default:
                break;
        }
    }

    /**
     * set the color of the previous selected image quality
     */
    private void resumeImageQualityStatus(int selectType) {
        switch (selectType) {
            case QUALITY_BASIC:
                radioViewBasic.setTextColor(this.getResources().getColor(R.color.cas_white));
                break;
            case QUALITY_MAIN:
                radioViewMain.setTextColor(this.getResources().getColor(R.color.cas_white));
                break;
            case QUALITY_BEST:
                radioViewBest.setTextColor(this.getResources().getColor(R.color.cas_white));
                break;
            default:
                break;
        }
    }

    /**
     * determine whether it is a horizontal screen
     */
    private boolean isLandscape() {
        Configuration mConfiguration = this.getResources().getConfiguration();
        int orientation = mConfiguration.orientation;
        if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
            return true;
        }
        return false;
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if ((keyCode == KeyEvent.KEYCODE_BACK)) {
            if (null != ctrView && ctrView.getVisibility() == View.VISIBLE) {
                ctrView.setVisibility(View.GONE);
                return true;
            }
            showUiLevelDialog();
            return true;
        } else if (keyCode == KeyEvent.KEYCODE_APP_SWITCH) {
            return true;
        } else if (keyCode == KeyEvent.KEYCODE_HOME) {
            return true;
        } else {
            return super.onKeyDown(keyCode, event);
        }
    }

    /**
     * stop cloud phone
     */
    private void stopCloudPhone() {
        CASLog.d(TAG, "stop cloud phone");
        doCheckConnection = false; //
        dismissAllDialogs();
        finish();
        gAcitivity = null;
        if (mVirtualDeviceSession != null) {
            mVirtualDeviceSession.stop();
        }
        new Thread(new Runnable() {
            @Override
            public void run() {
                bIsStart = false;
                try {
                    mCloudPhone.exitCloudPhone();
                } catch (Exception e) {
                    CASLog.e(TAG, "stop cloud phone failed " + e.getMessage());
                }
                if (mCasListener != null) {
                    mCasListener.onStateChange(CasState.CAS_EXIT, "Exit");
                }
            }
        }).start();
    }

    /**
     * Dialog:quit app
     */
    public void showUiLevelDialog() {
        if (quitDialog == null || !quitDialog.isShowing()) {
            final View contentView = View.inflate(this, R.layout.cas_set_ui_level, null);
            contentView.setAlpha(0.7f);

            final CasCommonDialog.Builder builder = new CasCommonDialog.Builder(this);
            CasCommonDialog.DialogClickListener dialogListener = new CasCommonDialog.DialogClickListener();

            builder.setTitle(R.string.cas_phone_quit_app_tip_message);
            builder.setContentView(contentView);
            builder.setPositiveButton(getResources().getString(R.string.cas_phone_cancel_tip_message), dialogListener);
            builder.setNegativeButton(getResources().getString(R.string.cas_phone_quit_app_tip_message), new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    CASLog.i(TAG, "showUiLevelDialog stopCloudPhone");
                    stopCloudPhone();
                }
            });

            quitDialog = builder.create();
            quitDialog.setCancelable(true);
            if (!CasCloudPhoneActivity.this.isFinishing()) {
                quitDialog.show();
            }
        }
    }

    public void showDialog(String message) {
        final CasCommonDialog.Builder builder = new CasCommonDialog.Builder(this);
        CasCommonDialog.DialogClickListener dialogListener = new CasCommonDialog.DialogClickListener();
        builder.setTitle(R.string.cas_phone_tip);
        builder.setMessage(message);
        builder.setPositiveButton(R.string.cas_phone_quit_app_tip_message, dialogListener);

        mDialog = builder.create();
        mDialog.setCanceledOnTouchOutside(false);
        mDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
            @Override
            public void onDismiss(DialogInterface dialog) {
                stopCloudPhone();
            }
        });
        if (!CasCloudPhoneActivity.this.isFinishing()) {
            mDialog.show();
        }
    }

    /**
     * Dialog:dismiss all
     */
    public void dismissAllDialogs() {
        CASLog.i(TAG, "dismiss all dialogs.");
        if (null != quitDialog && quitDialog.isShowing()) {
            quitDialog.dismiss();
            quitDialog = null;
        }

        if (null != mDialog && mDialog.isShowing()) {
            mDialog.dismiss();
            mDialog = null;
        }
    }

    /**
     * 启动成功后处理任务
     */
    private void startSuccessThreadTask() {
        doCheckConnection = true;
        bIsStart = true;
        rebuildDone = false;
        // monitor network
        new Thread(new Runnable() {
            @Override
            public void run() {
                mIsStartTaskRunning = true;
                CASLog.i(TAG, "startSuccessThreadTask in");
                while (bIsStart) {
                    sleep(200);
                    final int lagVal = mCloudPhone.getRtt();
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            setLagText(lagVal);
                        }
                    });
                }
                CASLog.i(TAG, "startSuccessThreadTask out");
                mIsStartTaskRunning = false;
            }
        }).start();
    }

    /**
     * resident lag
     */
    private void setLagText(int lagVal) {
        if (!isShowingLagInfoView) return;
        String lagContent = String.valueOf(lagVal);
        if (lagVal > REFERENCE_LAG_MAX_VALUE || lagVal <= REFERENCE_LAG_ZERO_VALUE) {
            lagContent = "*";
        }

        if (lagVal > REFERENCE_LAG_MID_VALUE) {
            textCtrl.setTextColor(Color.RED);
        } else if (lagVal > REFERENCE_LAG_MIN_VALUE) {
            textCtrl.setTextColor(Color.YELLOW);
        } else if (lagVal > REFERENCE_LAG_ZERO_VALUE) {
            textCtrl.setTextColor(Color.GREEN);
        } else {
            textCtrl.setTextColor(Color.RED);
        }
        textCtrl.setText(lagContent);
    }

    @Override
    public void onClick(View view) {
        int id = view.getId();
        if (id == R.id.tv_ctrl) {
            switchCtrlViewShow();
        } else if (id == R.id.quit_cloud_phone) {
            showUiLevelDialog();
            switchCtrlViewShow();
        } else if (id == R.id.ctr_view) {
            switchCtrlViewShow();
        } else if (id == R.id.lag_switch) {
            updateLagInfoViewState(lagSwitch.isChecked());
        }
    }

    class CloudPhoneOrientationListener implements CloudPhoneOrientationChangeListener {
        @Override
        public void onOrientationChange(int msg) {
            Message message = new Message();
            message.what = CHANGE_ROTA;
            message.arg1 = msg;
            handler.sendMessage(message);
        }
    }

    class CloudPhoneStateListenerImpl implements CloudPhoneStateListener {
        @Override
        public void onNotify(int code, String msg) {
            CASLog.i(TAG, "code = " + code + " msg = " + msg);
            Message message = new Message();
            message.what = MSG_STATE_CHANGE;
            message.arg1 = code;
            message.obj = msg;
            handler.sendMessage(message);
            if (mCasListener != null) {
                mCasListener.onStateChange(code, msg);
            }
            // debug版本，显示调试toast
            if (BuildConfig.IS_DEBUG) {
                final String toastMessage = msg;
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast toast = Toast.makeText(CasCloudPhoneActivity.this, toastMessage, Toast.LENGTH_SHORT);
                        toast.setGravity(Gravity.CENTER, 0, 0);
                        toast.show();
                    }
                });
            }
        }
    }

    class CloudPhoneVirtualDevDataListenerImpl implements CloudPhoneVirtualDevDataListener {

        @Override
        public void onRecvVirtualDevData(byte[] data, int length) {
            if (mRingBufferVirtualDeviceIO != null) {
                mRingBufferVirtualDeviceIO.fillData(data);
            }
        }
    }

    public void switchCtrlViewShow() {
        if (ctrView == null) {
            return;
        }
        if (ctrView.getVisibility() == View.GONE) {
            ctrView.setVisibility(View.VISIBLE);
        } else {
            ctrView.setVisibility(View.GONE);
        }
    }
}